<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>课堂练习</title>
    <style>
        body {
            font-family: "Segoe UI", "Microsoft YaHei", sans-serif;
            background: #f5f7fa;
            margin: 0;
            padding: 0;
        }
        .floating-sidebar {
            position: fixed;
            top: 32px;
            left: 32px;
            width: 110px;
            background: #fff;
            border-radius: 10px;
            box-shadow: 0 2px 12px #0001;
            padding: 18px 10px 18px 10px;
            z-index: 1000;
            display: flex;
            flex-direction: column;
            align-items: center;
        }
        .sidebar-title {
            font-weight: bold;
            color: #1976d2;
            margin-bottom: 12px;
            font-size: 1.1em;
            letter-spacing: 1px;
        }
        .sidebar-nums {
            display: flex;
            flex-wrap: wrap;
            gap: 8px;
            justify-content: center;
        }
        .sidebar-num {
            width: 32px;
            height: 32px;
            display: flex;
            align-items: center;
            justify-content: center;
            border-radius: 50%;
            background: #f3f3f3;
            color: #1976d2;
            font-weight: bold;
            font-size: 16px;
            border: 2px solid #e0e0e0;
            cursor: pointer;
            transition: background 0.2s, color 0.2s;
            margin-bottom: 2px;
        }
        .sidebar-num.done {
            background: #c8e6c9;
            color: #388e3c;
            border-color: #81c784;
        }
        .sidebar-num.wrong {
            background: #ffcdd2;
            color: #c62828;
            border-color: #e57373;
        }
        .sidebar-num.active {
            background: #1976d2;
            color: #fff;
            border-color: #1976d2;
        }
        .container {
            max-width: 820px;
            margin: 48px auto 32px auto;
            background: #fff;
            border-radius: 12px;
            box-shadow: 0 4px 24px #0001;
            padding: 32px 32px 24px 32px;
            position: relative;
            min-height: 600px;
        }
        .header h1 {
            text-align: center;
            font-size: 2.1em;
            color: #1976d2;
            margin-bottom: 32px;
            letter-spacing: 2px;
        }
        .question-section {
            margin-bottom: 32px;
        }
        .section-title {
            font-size: 1.15em;
            color: #1976d2;
            margin-bottom: 10px;
            letter-spacing: 1px;
        }
        .question {
            margin-bottom: 18px;
            border-radius: 8px;
            padding: 16px 18px 12px 18px;
            transition: background 0.2s;
            background: #f9f9fb;
            box-shadow: 0 1px 4px #0001;
        }
        .question.done {
            background: #e8f5e9;
        }
        .question.wrong {
            background: #fdeaea;
        }
        .question-number {
            font-weight: bold;
            margin-right: 6px;
            color: #1976d2;
        }
        .options {
            margin: 8px 0 0 0;
        }
        .option {
            margin-bottom: 6px;
            display: flex;
            align-items: center;
            cursor: pointer;
        }
        .option label {
            margin-left: 6px;
            cursor: pointer;
            font-size: 1em;
        }
        .option.correct label {
            color: #1976d2;
            font-weight: bold;
        }
        .option.incorrect label {
            color: #e74c3c;
        }
        .btn-group {
            margin: 32px 0 0 0;
            text-align: center;
        }
        .btn {
            padding: 10px 28px;
            border-radius: 4px;
            border: none;
            font-size: 17px;
            margin: 0 12px;
            cursor: pointer;
            box-shadow: 0 2px 8px #1976d220;
            transition: background 0.2s;
        }
        .btn-primary {
            background: #1976d2;
            color: #fff;
        }
        .btn-primary:hover {
            background: #1565c0;
        }
        .btn-secondary {
            background: #eee;
            color: #333;
        }
        .btn-secondary:hover {
            background: #ddd;
        }
        .result {
            display: none;
            margin-top: 32px;
            text-align: center;
        }
        .result.show {
            display: block;
        }
        .correct-answer {
            color: #388e3c;
            margin-top: 4px;
            font-size: 1em;
        }
        .explanation {
            color: #888;
            font-size: 14px;
            display: none;
            margin-top: 2px;
        }
        .explanation.show {
            display: block;
        }
        @media (max-width: 900px) {
            .container { padding-left: 10px; }
            .floating-sidebar { position: static; width: 100%; flex-direction: row; justify-content: flex-start; margin-bottom: 18px; }
        }
        @media (max-width: 600px) {
            .container { padding: 10px 2vw; }
            .floating-sidebar { padding: 8px 2vw; }
        }
    </style>
</head>
<body>
    <div class="floating-sidebar" id="sidebar"></div>
    <div class="container">
        <div class="header">
            <h1>课堂练习</h1>
        </div>
        <div class="card"></div>
    </div>
    <script>
        // 题库示例
        const questions = [
            {
                type: 'judge',
                section: '一、判断题',
                items: [
                    {
                        text: '互联网在形成阶段实现了TCP/IP协议的标准化。',
                        options: [{ value: 'A', label: '正确' }, { value: 'B', label: '错误' }],
                        answer: 'B',
                        explanation: 'TCP/IP协议标准化是在互联阶段实现的，形成阶段的标志是阿帕网（ARPA Net）诞生。'
                    },
                    {
                        text: '5G技术具有高速率、低时延、大容量的特点。',
                        options: [{ value: 'A', label: '正确' }, { value: 'B', label: '错误' }],
                        answer: 'A',
                        explanation: '5G技术是目前最先进的移动通信技术，具有高速率、低时延、容量大等特点。'
                    }
                ]
            },
            {
                type: 'single',
                section: '二、单项选择题',
                items: [
                    {
                        text: '互联网发展的哪个阶段实现了TCP/IP协议标准化？',
                        options: [
                            { value: 'A', label: '诞生阶段' },
                            { value: 'B', label: '形成阶段' },
                            { value: 'C', label: '互联阶段' },
                            { value: 'D', label: '高速网络阶段' }
                        ],
                        answer: 'C',
                        explanation: '在互联阶段，TCP/IP协议实现标准化，成为互联网的基础协议。'
                    }
                ]
            },
            {
                type: 'multi',
                section: '三、多项选择题',
                items: [
                    {
                        text: '下列哪些属于互联网基础协议？（多选）',
                        options: [
                            { value: 'A', label: 'TCP' },
                            { value: 'B', label: 'IP' },
                            { value: 'C', label: 'HTTP' },
                            { value: 'D', label: 'SMTP' }
                        ],
                        answer: ['A', 'B', 'D'],
                        explanation: 'TCP、IP、SMTP 都是互联网基础协议，HTTP 属于应用层协议。'
                    }
                ]
            }
        ];

        // 自动生成 number 字段
        (function autoNumberQuestions() {
            let num = 1;
            questions.forEach(section => {
                section.items.forEach(item => {
                    item.number = num++;
                });
            });
        })();

        // 生成所有题号数组
        let allQuestionRefs = [];
        (function buildQuestionRefs() {
            allQuestionRefs = [];
            questions.forEach(section => {
                section.items.forEach(item => {
                    let name;
                    if (section.type === 'judge') name = `t${item.number}`;
                    else if (section.type === 'single') name = `q${item.number}`;
                    else if (section.type === 'multi') name = `m${item.number}`;
                    allQuestionRefs.push({ name, number: item.number });
                });
            });
        })();

        // 渲染题目和题号板块
        function renderQuestions() {
            // 渲染题号板块
            const sidebar = document.getElementById('sidebar');
            sidebar.innerHTML = `
                <div class="sidebar-title">题号</div>
                <div class="sidebar-nums">
                    ${allQuestionRefs.map(q => `<span class="sidebar-num" data-qref="${q.name}">${q.number}</span>`).join('')}
                </div>
            `;
            // 渲染题目
            const card = document.querySelector('.card');
            card.innerHTML = `<div id="questions"></div>
                <div class="btn-group">
                    <button class="btn btn-primary" id="submit">提交答案</button>
                    <button class="btn btn-secondary" id="reset">重置</button>
                </div>
                <div class="result" id="result">
                    <h3 class="correct">答题完成！共答对 <span id="score">0</span> 题</h3>
                </div>
            `;
            const questionsDiv = card.querySelector('#questions');
            let html = '';
            questions.forEach(section => {
                html += `<div class="question-section"><h2 class="section-title">${section.section}</h2>`;
                section.items.forEach(item => {
                    let name;
                    if (section.type === 'judge') name = `t${item.number}`;
                    else if (section.type === 'single') name = `q${item.number}`;
                    else if (section.type === 'multi') name = `m${item.number}`;
                    html += `
                        <div class="question" id="question-${name}">
                            <p><span class="question-number" id="qn-${name}">${item.number}</span>${item.text}</p>
                            ${
                                section.type === 'judge' || section.type === 'single' ?
                                `<div class="options">
                                    ${item.options.map(opt => `
                                        <div class="option">
                                            <input type="radio" name="${name}" value="${opt.value}" id="${name}-${opt.value}">
                                            <label for="${name}-${opt.value}">${opt.value}. ${opt.label}</label>
                                        </div>
                                    `).join('')}
                                </div>` : ''
                            }
                            ${
                                section.type === 'multi' ?
                                `<div class="options">
                                    ${item.options.map(opt => `
                                        <div class="option">
                                            <input type="checkbox" name="${name}" value="${opt.value}" id="${name}-${opt.value}">
                                            <label for="${name}-${opt.value}">${opt.value}. ${opt.label}</label>
                                        </div>
                                    `).join('')}
                                </div>` : ''
                            }
                            <div class="correct-answer" id="ans-${name}"></div>
                            <div class="explanation" id="exp-${name}">解析：${item.explanation}</div>
                        </div>
                    `;
                });
                html += '</div>';
            });
            questionsDiv.innerHTML = html;

            // 题号点击跳转
            sidebar.querySelectorAll('.sidebar-num').forEach(span => {
                span.onclick = function () {
                    const qid = 'question-' + span.dataset.qref;
                    const qel = document.getElementById(qid);
                    if (qel) {
                        window.scrollTo({ top: qel.getBoundingClientRect().top + window.scrollY - 40, behavior: 'smooth' });
                        // 高亮当前题号
                        sidebar.querySelectorAll('.sidebar-num').forEach(s => s.classList.remove('active'));
                        span.classList.add('active');
                    }
                };
            });
        }
        renderQuestions();

        // 生成正确答案映射
        const correctAnswers = {};
        questions.forEach(section => {
            section.items.forEach(item => {
                let name;
                if (section.type === 'judge') name = `t${item.number}`;
                else if (section.type === 'single') name = `q${item.number}`;
                else if (section.type === 'multi') name = `m${item.number}`;
                correctAnswers[name] = section.type === 'multi' ? item.answer : item.answer;
            });
        });

        // 更新题号板块和题目背景
        function updateProgress(wrongSet) {
            allQuestionRefs.forEach(q => {
                let done = false;
                const inputType = Array.isArray(correctAnswers[q.name]) ? 'checkbox' : 'radio';
                if (inputType === 'radio') {
                    done = !!document.querySelector(`input[name="${q.name}"]:checked`);
                } else {
                    done = document.querySelectorAll(`input[name="${q.name}"]:checked`).length > 0;
                }
                // 题号高亮
                const numEl = document.querySelector(`.sidebar-num[data-qref="${q.name}"]`);
                if (numEl) {
                    numEl.classList.toggle('done', done && !(wrongSet && wrongSet.has(q.name)));
                    numEl.classList.toggle('wrong', wrongSet && wrongSet.has(q.name));
                }
                // 题目背景高亮
                const qEl = document.getElementById(`question-${q.name}`);
                if (qEl) {
                    qEl.classList.toggle('done', done && !(wrongSet && wrongSet.has(q.name)));
                    qEl.classList.toggle('wrong', wrongSet && wrongSet.has(q.name));
                }
            });
        }

        // 判分
        function validateAnswers() {
            let score = 0;
            let wrongSet = new Set();
            for (const [question, answer] of Object.entries(correctAnswers)) {
                const ansEl = document.getElementById(`ans-${question}`);
                const expEl = document.getElementById(`exp-${question}`);
                if (question.startsWith('m')) {
                    // 多选题
                    const selected = Array.from(document.querySelectorAll(`input[name="${question}"]:checked`)).map(i => i.value).sort();
                    const correct = answer.slice().sort();
                    ansEl.textContent = `正确答案：${correct.join('、')}`;
                    expEl.classList.add('show');
                    correct.forEach(val => {
                        const opt = document.querySelector(`input[name="${question}"][value="${val}"]`);
                        if (opt) opt.closest('.option').classList.add('correct');
                    });
                    selected.forEach(val => {
                        if (!correct.includes(val)) {
                            const opt = document.querySelector(`input[name="${question}"][value="${val}"]`);
                            if (opt) opt.closest('.option').classList.add('incorrect');
                        }
                    });
                    if (selected.length && selected.join(',') === correct.join(',')) {
                        score++;
                    } else {
                        wrongSet.add(question);
                    }
                } else {
                    // 单选/判断题
                    const selectedOption = document.querySelector(`input[name="${question}"]:checked`);
                    ansEl.textContent = `正确答案：${answer}`;
                    expEl.classList.add('show');
                    const correctOption = document.querySelector(`input[name="${question}"][value="${answer}"]`);
                    if (correctOption) correctOption.closest('.option').classList.add('correct');
                    if (selectedOption) {
                        if (selectedOption.value === answer) {
                            score++;
                        } else {
                            selectedOption.closest('.option').classList.add('incorrect');
                            wrongSet.add(question);
                        }
                    } else {
                        wrongSet.add(question);
                    }
                }
            }
            document.getElementById('score').textContent = score;
            document.getElementById('result').classList.add('show');
            updateProgress(wrongSet);
        }

        // 重置
        function resetQuiz() {
            document.querySelectorAll('input[type="radio"],input[type="checkbox"]').forEach(input => {
                input.checked = false;
                const optionEl = input.closest('.option');
                if (optionEl) optionEl.classList.remove('correct', 'incorrect');
            });
            Object.keys(correctAnswers).forEach(question => {
                const ansEl = document.getElementById(`ans-${question}`);
                const expEl = document.getElementById(`exp-${question}`);
                if (ansEl) ansEl.textContent = "";
                if (expEl) expEl.classList.remove('show');
            });
            document.getElementById('result').classList.remove('show');
            updateProgress();
        }

        // 监听选项变化
        document.querySelector('.card').addEventListener('change', function (e) {
            if (
                e.target.type === 'radio' ||
                e.target.type === 'checkbox'
            ) {
                updateProgress();
            }
        });

        // 监听提交按钮
        document.querySelector("#submit").addEventListener('click', validateAnswers);
        // 监听重置按钮
        document.querySelector("#reset").addEventListener('click', resetQuiz);
        // 初始化进度
        updateProgress();
    </script>
</body>
</html>